<?php
/**
 * QPay.class.php
 *
 * @author camfee <camfee@foxmail.com>
 * @date   18-1-17 下午6:23
 *
 */

namespace controls\MobileApi\Payment;

use Center\CoinLog;
use Center\Goods;
use Center\Payment;
use Center\User;
use MobileApi\ApiBase;

/**
 * qq钱包支付相关
 *
 * @package Payment
 * @author  camfee<camfee@foxmail>
 */
class QPay extends ApiBase
{
    /**
     * 创建预支付订单
     *
     * <pre>
     * POST
     *      product_id: 购买商品的id
     * </pre>
     *
     * @return string|void json
     *
     * <pre>
     * {
     *     "Status": 200,
     *     "Result": {
     *         "Sn": "50118012122394820012951506204104",
     *         "PrepayId": "5V051f9219c0d70c749456f7a5065208",
     *         "Package": {
     *             "appId": "1106497884",
     *             "nonce": "y37fldmb21s714p8jfbxn21cr19853e6",
     *             "tokenId": "5V051f9219c0d70c749456f7a5065208",
     *             "bargainorId": "1491082901",
     *             "pubAcc": "",
     *             "sig": "F70DD21C0B8918916D59D2B5E3331A2B",
     *             "timeStamp": "1516545588",
     *             "sigType": "HMAC-SHA1",
     *             "pubAccHint": ""
     *         }
     *     },
     *     "ServerTime": 1516545588
     * }
     *  异常情况
     * 201: 购买的商品不存在
     * 212: 网络错误
     * 213: 数据错误
     * </pre>
     */
    public function create()
    {
        $uid = $this->isLogin(true);
        $product_id = trim($_POST['product_id']);
        $app_id = $GLOBALS['g_appid'];
        $device_id = $GLOBALS['g_deviceid'];
        $channel = $GLOBALS['g_channel'];

        $product_info = Goods::getInfoByIds($product_id);
        if (empty($product_info)) {
            debug_log("qpay buy {$product_id} not exist");
            $this->output(201, '购买商品不存在');
        }
        $goods_title = $product_info['Title'];
        $price = $product_info['Price'] * 100;
        $sn = Payment::generateSN($app_id, Payment::PAY_TYPE_WEIXIN, $channel);

        //发起api请求
        $res = \lib\plugins\qpay\QPay::unified([
            "out_trade_no" => $sn,
            "body" => $goods_title,
            "total_fee" => $price,
            "trade_type" => 'APP',
            'spbill_create_ip' => self::clientIp(),
        ]);
        if (empty($res)) {
            debug_log("Qpay buy request unified error", JF_LOG_WARNING);
            $this->output(212, '网络错误1');
        }
        $msg = 'OK';
        if ($res['return_code'] != 'SUCCESS' || $res['result_code'] != 'SUCCESS') {
            debug_log("Qpay buy unified response error, {$msg}", JF_LOG_WARNING);
            $this->output(212, '网络错误2');
        }
        //创建payments model
        $prepay_id = $res['prepay_id'];
        $params = [
            'AppId' => $app_id,
            'DeviceId' => $device_id,
            'UserId' => $uid,
            'GoodsInfo' => $goods_title,
            'SN' => $sn,
            'ProductId' => $product_id,
            'PaymentType' => Payment::PAY_TYPE_QPAY,
            'TradeNo' => $prepay_id,
            'TotalFee' => $price,
            'Status' => Payment::STATUS_WAIT_PAY,
        ];
        $ret = Payment::add($params);
        if ($ret === false) {
            debug_log(["qpay buy addPayment failed, ret: {$ret}", $params], JF_LOG_ERROR);
            $this->output(213, '数据错误');
        }

        debug_log("qpay buy addPayment, uid: {$uid}, appId: {$app_id}, productId: {$product_id}");
        //获取请求结果，生成app调用支付签名包
        $this->output(200, [
            'Sn' => $sn,
            "PrepayId" => $prepay_id,
            'Package' => \lib\plugins\qpay\QPay::generatePackageParams($prepay_id)
        ]);
    }

    /**
     * 查询订单
     *
     * <pre>
     * POST
     *      sn: 必选， 交易流水号
     * </pre>
     *
     * @return string json
     *
     * <pre>
     * {
     *      "Status": 200,
     *      "Result": {}
     * }
     * 异常情况
     * 211: 请求参数错误
     * 212: 订单不存在
     * 213: 用户已取消支付
     * 214: 支付失败
     * 215: 网络错误
     * 216: 微信接口错误
     * 217: 正在支付当中 （客户端应该继续查询）
     * </pre>
     */
    public function query()
    {
        $uid = (int)$this->isLogin();
        $sn = $_POST['sn'];
        if (empty($sn)) {
            $this->output(211, '参数错误');
        }
        $payment_info = Payment::getInfoBySN($sn);
        if (empty($payment_info)) {
            $this->output(212, '订单不存在');
        }

        $payment_id = $payment_info['PaymentId'];
        $product_id = $payment_info['ProductId'];
        $product_info = Goods::getInfoByIds($product_id);
        if (empty($product_info)) {
            debug_log("qpay pay query productId:{$product_id} not exist", JF_LOG_ERROR);
            $this->output(212, '订单异常');
        }
        $old_status = $payment_info['Status'];
        if ($old_status == Payment::STATUS_PAY_CANCELED) {
            $this->output(213, '用户已取消支付');
        } elseif ($old_status == Payment::STATUS_PAY_FAILURE) {
            $this->output(214, '用户支付失败');
        } elseif ($old_status == Payment::STATUS_PAY_SUCCESS) {
            $this->output(200, '支付成功');
        }

        //发起api请求
        $res = \lib\plugins\qpay\QPay::query([
            'out_trade_no' => $sn
        ]);
        if (empty($res)) {
            debug_log("qpay pay request query failed, paymentId:{$payment_id}", JF_LOG_WARNING);
            $this->output(215, '网络错误1');
        }
        if (\lib\plugins\qpay\QPay::checkSign($res) === false) {
            debug_log("qpay pay query result sign error, msg:{$res['trade_state_desc']}", JF_LOG_WARNING);
            $this->output(216, '接口返回错误');
        }
        $trade_status = $res['trade_state'];
        if ($trade_status === 'USERPAYING') {
            $this->output(217, '正在支付中');

        } elseif ($trade_status === 'SUCCESS') {
            if (Payment::isFirstPay($uid)) {
                CoinLog::addCoinLog($uid, 2, CoinLog::TYPE_FIRST_PAY);
            }
            $data = [
                'ThirdSN' => $res['transaction_id'],
                'Content' => $res,
                'Status' => Payment::STATUS_PAY_SUCCESS,
                'UpdateTime' => date('Y-m-d H:i:s'),
            ];
            if (Payment::paySuccess($sn, $data) === 0) {
                $user_id = $payment_info['UserId'];
                $coin = (int)$product_info['JCoin'] + (int)$product_info['Donate'];
                pay_succ_log("paySuccess, paymentId:{$payment_id}, userId:{$user_id}");
                if (User::updateJCoin($user_id, $coin) === false) {
                    pay_fail_log("addBean failed, paymentId:{$payment_id}, userId:{$user_id}, Coin:{$coin}");
                    Payment::updatePaymentBySN($sn, ['Status' => Payment::STATUS_SEND_GOODS_FAILED]);
                } else {
                    CoinLog::addCoinLog($uid, $product_info['JCoin'], CoinLog::TYPE_EXCHANGE, false);
                    if (!empty($product_info['Donate'])) {
                        CoinLog::addCoinLog($uid, $product_info['Donate'], CoinLog::TYPE_PAY_DONATE, false);
                    }
                    pay_succ_log("addBean, paymentId:{$payment_id}, userId:{$user_id}, Coin:{$coin}");
                }
            } else {
                pay_fail_log("paySuccess failed, paymentId:{$payment_id}, uid:{$uid}");
            }
            $this->output(200, '支付成功');

        } elseif ($trade_status === 'REVOKED') {
            debug_log("qpay pay query failed, paymentId:{$payment_id}, status:{$trade_status}", JF_LOG_WARNING);
            Payment::updatePaymentBySN($sn, ['Status' => Payment::STATUS_PAY_CANCELED]);
            $this->output(213, $res['trade_state_desc']);

        } else {
            debug_log("qpay pay query failed, paymentId:{$payment_id}, status:{$trade_status}", JF_LOG_WARNING);
            Payment::updatePaymentBySN($sn, ['Status' => Payment::STATUS_PAY_FAILURE]);
            $this->output(214, $res['trade_state_desc']);
        }
        exit;
    }
}